#ifndef __MVT_SJSON_H__
#define __MVT_SJSON_H__

#include "mvdef.h"

MVCXX_EXTERN_BEGIN

/*********************************************************
 *
 *        SJSON 高层解析API，内部基于DSJON封装实现
 *                      更简单使用方法
 *
 ********************************************************/
typedef enum _sjson_type_of_value
{
    SJVT_INVALID   =   0, 
    SJVT_BOOL      =   1, ///<true / false
    SJVT_INT8      =   2, ///<v8 / s8
    SJVT_INT16     =   3, ///<s16
    SJVT_INT32     =   4, ///<s32
    SJVT_UINT8     =   5, ///<u8
    SJVT_UINT16    =   6, ///<u16
    SJVT_UINT32    =   7, ///<u32
    SJVT_FLOAT     =   8, ///<float(不推荐使用，此类型转换函数都是转double，由double转float会有小数位误差)
    SJVT_DOUBLE    =   9, ///<double
    SJVT_INT64     =  10, ///<s64
    SJVT_UINT64    =  11, ///<u64
    SJVT_STRING    =  12, ///<string
    SJVT_ARRAY     =  13, ///<array
    SJVT_OBJECT    =  14, ///<object
    SJSON_VALUE_TYPE_NUM,
    SJSON_VALUE_TYPE_END  =  (SJSON_VALUE_TYPE_NUM-1),
}mvt_sjson_vtype_e;
typedef mv_void_t(*pf_kv_output_handler)(mv_vptr_t p_output, mv_s32_t s32_type_identify, mv_v8ptr_t pv8_str_data, mv_s32_t s32_len);;
mv_void_t mvt_sjson_array_output_handler (mv_vptr_t p_output, mv_s32_t s32_size, mv_v8ptr_t pv8_str_data, mv_s32_t s32_len);
mv_void_t mvt_sjson_object_output_handler(mv_vptr_t p_output, mv_s32_t s32_size, mv_v8ptr_t pv8_str_data, mv_s32_t s32_len);
mv_void_t mvt_sjson_string_output_handler(mv_vptr_t p_output, mv_s32_t s32_size, mv_v8ptr_t pv8_str_data, mv_s32_t s32_len);
mv_void_t mvt_sjson_value_output_handler (mv_vptr_t p_output, mv_s32_t s32_type, mv_v8ptr_t pv8_str_data, mv_s32_t s32_len);
mv_void_t mvt_sjson_bool_output_handler  (mv_vptr_t p_output, mv_s32_t s32_type, mv_v8ptr_t pv8_str_data, mv_s32_t s32_len);

/**
 * @brief 普通字符串 转义成 json字符串
 * 
 * @param [in] pv8_dst : 转义后字符串数据缓冲区
 * @param [in] s32_dst_max_len : 转义后数据最大长度
 * @param [in] pv8_src : 待处理字符串数据
 * @param [in] s32_src_len : 待处理字符串数据长度
 * @return 转义后长度
 * - success: >= s32_src_len
 * -  failed: <  s32_src_len (缓冲区长度不足)
 * 
 * @note 注意没有多余空间预留时，结尾不会自动补'\0'
 */
mv_s32_t mvt_string_transfer_json_content(mv_v8ptr_t pv8_dst, mv_s32_t s32_dst_max_len, mv_cv8ptr_t cpv8_src, mv_s32_t s32_src_len);
/**
 * @brief json字符串 去转义成 普通字符串
 * 
 * @param [in] pv8_dst : 去转义后字符串数据缓冲区
 * @param [in] s32_dst_max_len : 去转义后数据最大长度
 * @param [in] pv8_src : 待处理字符串数据
 * @param [in] s32_src_len : 待处理字符串数据长度
 * @return 去转义后长度
 * - success: > 0
 * -  failed: = 0 (格式不符，转义符后无字符数据)
 * 
 * @note 由于去转义操作，结果长度 <= s32_src_len，所以结果缓冲区可以使用源数据缓冲区 (注意相等时，结尾不会自动补'\0')
 */
mv_s32_t mvt_json_content_transfer_string(mv_v8ptr_t pv8_dst, mv_s32_t s32_dst_max_len, mv_cv8ptr_t cpv8_src, mv_s32_t s32_src_len);

typedef struct _kv_node {
    mv_v8ptr_t pv8_key;             ///<关键字
    mv_u8_t    u8_check;            ///<是否必须存在（启用，则若该key不存在，会返回NOT FOUND类型错误）
    mv_s32_t   s32_cursor;          ///<key匹配游标
    mv_v8ptr_t pv8_content;         ///<content起始位置
    mv_s32_t   s32_len;             ///<content长度
    mv_vptr_t  p_output_cache;      ///<content起始位置转换成目标类型的存储缓冲区（非空时，配合@s32_size_or_vtype使用，转换出需要的类型数据）
    mv_s32_t   s32_size_or_vtype;   ///<数值类存储缓冲区数据类型 或 字符串/数组/对象类存储缓冲区大小
    pf_kv_output_handler f_kv_output;  ///<目标类型对应转换函数
}mvt_sjkv_node_t;
/** 目标匹配表定义宏 */
#define sjkv_table_def(name, ...)              \
mvt_sjkv_node_t _astru_sjkv_##name##_tb[] = {\
    sjkv_string("", NULL, 0),                  \
    ##__VA_ARGS__                              \
}
/** 可用此宏简化填充 mvt_sjson_parser 的2、3参数 */
#define sjkv_table(name)    _astru_sjkv_##name##_tb
#define sjkv_item_num(name) (sizeof(_astru_sjkv_##name##_tb)/sizeof(_astru_sjkv_##name##_tb[0]))
/** 根据表名和目标key对应序号，提取出content地址和长度；(注意：使用了子对象拆解的object类型，取出来的content会不完整；因为已经被拆解掉了) */
#define sjkv_item_type(tbname, idx)        _astru_sjkv_##tbname##_tb[idx+1].s32_size_or_vtype
#define sjkv_item_content(tbname, idx)     _astru_sjkv_##tbname##_tb[idx+1].pv8_content
#define sjkv_item_content_len(tbname, idx) _astru_sjkv_##tbname##_tb[idx+1].s32_len

/**
 * @brief sjkv 的 布尔类型 item
 * 
 * @param key      [in] 目标关键字
 * @param p_output [in] (可选)目标数值的存储缓冲区
 * @param sjvt     [in] (同上)目标数据的数据类型 [SJVT_BOOL]
 * @see sjkv_bool_chk 该关键字必须存在且类型符合
 */
#define sjkv_bool(key, p_output, sjvt)     {.pv8_key=key, .u8_check=0, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)p_output, .s32_size_or_vtype=sjvt, .f_kv_output=mvt_sjson_bool_output_handler}
#define sjkv_bool_chk(key, p_output, sjvt) {.pv8_key=key, .u8_check=1, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)p_output, .s32_size_or_vtype=sjvt, .f_kv_output=mvt_sjson_bool_output_handler}
/**
 * @brief sjkv 的 数值类型 item
 * 
 * @param key      [in] 目标关键字
 * @param p_output [in] (可选)目标数值的存储缓冲区
 * @param sjvt     [in] (同上)目标数据的数据类型 [SJVT_INT8 ~ SJVT_UINT64]
 * @see sjkv_value_chk 该关键字必须存在且类型符合
 */
#define sjkv_value(key, p_output, sjvt)     {.pv8_key=key, .u8_check=0, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)p_output, .s32_size_or_vtype=sjvt, .f_kv_output=mvt_sjson_value_output_handler}
#define sjkv_value_chk(key, p_output, sjvt) {.pv8_key=key, .u8_check=1, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)p_output, .s32_size_or_vtype=sjvt, .f_kv_output=mvt_sjson_value_output_handler}
/**
 * @brief sjkv 的 字符串类型 item
 * 
 * @param key        [in] 目标关键字
 * @param p_output   [in] 字符串数据存储缓冲区
 * @param cache_size [in] 字符串数据缓冲区大小
 * @see sjkv_string_chk 该关键字必须存在且类型符合
 */
#define sjkv_string(key,p_output, cache_size)     {.pv8_key=key, .u8_check=0, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)p_output, .s32_size_or_vtype=cache_size, .f_kv_output=mvt_sjson_string_output_handler}
#define sjkv_string_chk(key,p_output, cache_size) {.pv8_key=key, .u8_check=1, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)p_output, .s32_size_or_vtype=cache_size, .f_kv_output=mvt_sjson_string_output_handler}
/**
 * @brief sjkv 的 数组类型 item
 * @param key       [in] 目标关键字
 * @param sub_table [in] (可选)目标子object匹配表
 * @param item_num  [in] (跟随)目标子object的item数量
 * @note sub_table和item_num可以使用[sjkv_subtable]进行简化填充
 * @note 如需要直接解析子object，则sub_table和item_num填充正确内容；（此时单次解析过程子对象内容会自动分布到目标list中）
 * @note 否则，sub_table=NULL, item_num=0 即可使用分段解析（子对象不会进行拆解)
 * @see sjkv_array_chk 该关键字必须存在且类型符合
 */
#define sjkv_array(key,sub_table,item_num)     {.pv8_key=key, .u8_check=0, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)sub_table, .s32_size_or_vtype=item_num, .f_kv_output=mvt_sjson_array_output_handler}
#define sjkv_array_chk(key,sub_table,item_num) {.pv8_key=key, .u8_check=1, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)sub_table, .s32_size_or_vtype=item_num, .f_kv_output=mvt_sjson_array_output_handler}
/**
 * @brief sjkv 的 子对象(子json)类型 item
 * @param key       [in] 目标关键字
 * @param sub_table [in] (可选)目标子object匹配表
 * @param item_num  [in] (跟随)目标子object的item数量
 * @note sub_table和item_num可以使用[sjkv_subtable]进行简化填充
 * @note 如需要直接解析子object，则sub_table和item_num填充正确内容；（此时单次解析过程子对象内容会自动分布到目标list中）
 * @note 否则，sub_table=NULL, item_num=0 即可使用分段解析（子对象不会进行拆解)
 * @see sjkv_object_chk 该关键字必须存在且类型符合
 */
#define sjkv_object(key,sub_table,item_num)     {.pv8_key=key, .u8_check=0, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)sub_table, .s32_size_or_vtype=item_num, .f_kv_output=mvt_sjson_object_output_handler}
#define sjkv_object_chk(key,sub_table,item_num) {.pv8_key=key, .u8_check=1, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=(mv_vptr_t)sub_table, .s32_size_or_vtype=item_num, .f_kv_output=mvt_sjson_object_output_handler}
/**
 * @brief sjkv 的 任意类型 item（反向指定类型）
 * @param key        [in] 目标关键字
 * @note 会自动根据实际数据解析，刷新s32_size_or_vtype,调用者可以根据此类型结果使用handler系列API进行二次转换
 * @note 配合使用的一般流程是sjkv_item_type获取类型，sjkv_item_content获取内容，sjkv_item_content_len获取长度，handler系列二次转换；
 * @see sjkv_volatile_chk 该关键字必须存在且类型符合
 */
#define sjkv_volatile(key)     {.pv8_key=key, .u8_check=0, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=NULL, .s32_size_or_vtype=SJVT_INVALID, .f_kv_output=mvt_sjson_string_output_handler}
#define sjkv_volatile_chk(key) {.pv8_key=key, .u8_check=1, .s32_cursor=0, .pv8_content=NULL, .s32_len=-1, .p_output_cache=NULL, .s32_size_or_vtype=SJVT_INVALID, .f_kv_output=mvt_sjson_string_output_handler}

/**
 * @brief 解析并根据目标规则表处理输入的json数据
 * 
 * @param [in] pv8_json : 需要处理的json数据
 * @param [in] pstru_table : 目标kv规则表
 * @param [in] s32_item_num : kv表的目标规则数量
 * @param [in] u8_modifiable : 0：数据只读； 1：数据允许更改（内部会使用'\0'修改内容用于截断每一个content结尾，令它可以直接输出）
 * @return 解析处理结果
 * - [success] MV_EC_SUCCESS
 * - [failed ] MV_EC_NOT_FOUND (check失败)
 *             MV_EC_IGNORE (json格式异常)
 */
mv_s32_t mvt_sjson_parser(mv_v8ptr_t pv8_json, mvt_sjkv_node_t pstru_table[], mv_s32_t s32_item_num, mv_u8_t u8_modifiable);
/**
 * @brief 解析并根据目标规则表处理输入的json数据(EX接口，支持指定长度输入)
 * 
 * @param [in] pv8_json : 需要处理的json数据
 * @param [in] s32_len  : 需要处理的json数据长度（0表示未知，内部自动计算）
 * @param [in] pstru_table : 目标kv规则表
 * @param [in] s32_item_num : kv表的目标规则数量
 * @param [in] u8_modifiable : 0：数据只读； 1：数据允许更改（内部会使用'\0'修改内容用于截断每一个content结尾，令它可以直接输出）
 * @return 解析处理结果
 * - [success] MV_EC_SUCCESS
 * - [failed ] MV_EC_NOT_FOUND (check失败)
 *             MV_EC_IGNORE (json格式异常)
 */
mv_s32_t mvt_sjson_parser_ex(mv_v8ptr_t pv8_json, mv_s32_t s32_len, mvt_sjkv_node_t pstru_list[], mv_s32_t s32_item_num, mv_u8_t u8_modifiable);

/*********************************************************
 *
 *        DJSON 低层解析API，更灵活和节省资源；
 *            但是额外调用逻辑代码需要更多
 *
 ********************************************************/
typedef enum _djson_type_of_value
{
    DJVT_INVALID   =   0, 
    DJVT_BOOL,                  ///< 布尔类型 (true / false)
    DJVT_NUMBER,                ///< 整数数值类型
    DJVT_FLOAT,                 ///< 浮点数值类型
    DJVT_STRING,                ///< 字符串类型(valstr不包含"")
    DJVT_ARRAY,                 ///< 数组类型(valstr包含[])
    DJVT_OBJECT,                ///< 对象类型(valstr包含{})
    DJSON_VALUE_TYPE_NUM,
    DJSON_VALUE_TYPE_END  =  (DJSON_VALUE_TYPE_NUM-1),
}mvt_djson_vtype_e;

typedef struct _djson_kv
{
    union {
        mv_cv8ptr_t cv8ptr_key;     ///< Key串起始引用地址
        mv_v8ptr_t  pv8_key;        ///< Key串起始引用地址   (实际内存可写则可以使用此声明)
    };
    union {
        mv_cv8ptr_t cv8ptr_valstr;  ///< Value串起始引用地址
        mv_v8ptr_t  pv8_valstr;     ///< Value串起始引用地址 (实际内存可写则可以使用此声明)
    };
    mv_s32_t    s32_vlen;       ///< Value串长度
    mv_s32_t    s32_klen;       ///< Key串长度
    mv_u8_t     u8_vtype;       ///< Value数据类型
    mv_u8_t     au8_reserve[2]; ///< （对齐保留）
}mvt_djson_kv_t;

typedef struct _djson_handle
{
    /** 内部数据，勿手动更改 */
    mv_s32_t       s32_json_len;///< 内置长度
    mv_s32_t       s32_offset;  ///< 当前偏移
    /** KV输出（每次成功获取会完整填充） */
    mvt_djson_kv_t kv;
}mvt_djson_hdl_t;

/**
 * @brief JSON格式内容合法性检查
 * 
 * @param cpv8_json [in] JSON字符串
 * @param s32_len   [in] （可选）字符串指定长度，0则表示全长（内部计算，稍微降低运行效率）
 * @return 检查结果
 * - success : 实际有效数据长度
 * -  failed : MV_EC_INVALID_ARGS (数据异常 / JSON格式非法)
 *             MV_EC_OUT_OF_RANGE (JSON格式非法)
 * @note      数组或对象均可作为输入自动识别；
 * @attention 入参字符串首字节必须为'[' 或 '{'
 */
mv_s32_t mvt_djson_format_check  (mv_cv8ptr_t cpv8_json, mv_s32_t s32_len);
/**
 * @brief JSON内容单次提取（数组型[]）
 * 
 * @param phdl_djson [in] djson操作句柄
 * @param cpv8_json  [in] JSON字符串
 * @param s32_len    [in] 字符串指定长度，必须有效（不确定情况下，也可从check接口获取回来）
 * @return 单次提取结果
 * - success : MV_EC_SUCCESS / MV_EC_EOF(建议配合结果长度判断)
 * -  failed : MV_EC_INVALID_ARGS (数据异常 / JSON格式非法)
 *             MV_EC_OUT_OF_RANGE (JSON格式非法)
 * @note MV_EC_EOF结果出现时表示已经解析到末尾，建议配合结果长度判断是否存在有效数据未使用；
 */
mv_s32_t mvt_djson_array_parser (mvt_djson_hdl_t *phdl_djson, mv_cv8ptr_t cpv8_json, mv_s32_t s32_len);
/**
 * @brief JSON内容单次提取（对象型{}）
 * 
 * @param phdl_djson [in] djson操作句柄
 * @param cpv8_json  [in] JSON字符串
 * @param s32_len    [in] 字符串指定长度，必须有效（不确定情况下，也可从check接口获取回来）
 * @return 单次提取结果
 * - success : MV_EC_SUCCESS / MV_EC_EOF(建议配合结果长度判断)
 * -  failed : MV_EC_INVALID_ARGS (数据异常 / JSON格式非法)
 *             MV_EC_OUT_OF_RANGE (JSON格式非法)
 * @note MV_EC_EOF结果出现时表示已经解析到末尾，建议配合结果长度判断是否存在有效数据未使用；
 */
mv_s32_t mvt_djson_object_parser(mvt_djson_hdl_t *phdl_djson, mv_cv8ptr_t cpv8_json, mv_s32_t s32_len);

/*********************************************************
 *
 *        MJSON 宏形式封装API，更灵活和节省资源；
 *            但是宏展开后的代码量会相对偏多
 *    封装目的是能以更接近目标json结构的直观形式编写代码
 *
 ********************************************************/
#if 0
/** 典型调用示例，输出结果：{"ok1":"test string","sub_obj":{"ok2":"rtmp:\/\/127.0.0.1\/live\/12345678","on1":1,"bool-type":true},"array":[{"arrobj1_str":"code insert key ok.","arronum1":999},{"key2":"test vol inside string","key1":888}],"vol_obj":{"key2":"test vol inside string","key1":888}} */
mv_s32_t    _demo_volatile_subobject(mv_v8ptr_t pv8_buff, mv_s32_t s32_size, mv_cv8ptr_t cpv8_key1, mv_s32_t s32_valnum, mv_cv8ptr_t cpv8_key2, mv_cv8ptr_t cpv8_valstr)
{
    mv_s32_t _s32_outlen = 0;
    mvt_mjson_object_build(pv8_buff, s32_size, _s32_outlen,
        mvt_mjson_str(cpv8_key2, cpv8_valstr);
        mvt_mjson_num(cpv8_key1, s32_valnum);
    );
    return _s32_outlen;
}
mv_cv8ptr_t _demo_code_inser_str()
{
    return "code insert key ok.";
}
mv_s32_t main(mv_void_t)
{
    mv_v8ptr_t _pv8_out = NULL;
    mv_v8_t    _av8_stack_cache[512];
    mv_s32_t   _s32_outlen = 0;

    mv_s32_t   _s32_anchor_jump  = 0;

    _pv8_out = _av8_stack_cache;

    mvt_mjson_object_build(_pv8_out, 512, _s32_outlen,
        mvt_mjson_str("ok1", "test string", mvos_strlen("test string"));
        mvt_mjson_obj("sub_obj",
            mvt_mjson_str("ok2", "rtmp://127.0.0.1/live/12345678");
            mvt_mjson_num("on1", 1);
            mvt_mjson_bool("bool-type", MV_TRUE);
        );
        mvt_mjson_arr("array",
            mvt_mjson_anon_obj(
                mvos_dbg_printf("demo: can do someting inside macro\n");
                mvt_mjson_str("arrobj1_str", _demo_code_inser_str());
                mvt_mjson_num("arronum1", 999);
            );
            mvt_mjson_back_anchor_update(_s32_anchor_jump);
            mvt_mjson_anon_obj(
                mvt_mjson_str("arrobj2_str", "inside key value");
                mvt_mjson_num("arronum2", 1234567890);
                mvt_mjson_double("double-type", 1.2345);
                // mvt_mjson_back_anchor_jump(_s32_anchor_1);  ///< 非法回溯 !!!
            );
            mvt_mjson_back_anchor_jump(_s32_anchor_jump);  ///< 正确回溯
            mvt_mjson_volatile("",{},
                _demo_volatile_subobject(mvt_mjson_volatile_ptr, mvt_mjson_volatile_valid, "key1", 888, "key2", "test anon vol inside string");
            );
        );
        mvt_mjson_volatile("vol_obj", {},
            _demo_volatile_subobject(mvt_mjson_volatile_ptr, mvt_mjson_volatile_valid, "key1", 888, "key2", "test vol inside string");
        );
    );

    if (_s32_outlen < 0) {
        mvos_dbg_printf("cjson build failed: %d\n", _s32_outlen);
    } else if (_pv8_out) {
        mvos_dbg_printf("output======>\n%s\n========= len: %d\n", _pv8_out, _s32_outlen);
    }
    if (_pv8_out != _av8_stack_cache) {
        mvos_free(_pv8_out);
    }

    return 0;
}
#endif

/**
 * 如遇到不支持的系统，可能需要额外条件编译并限制使用方式处理
 *（主要应对复杂build，build过程外部嵌套了多种while或者switch方法，导致无法直接抛出异常提前结束）
 * 如简单处理#define _mjson_break(res) break
 */
#include <setjmp.h>
#define _mjson_break longjmp(_tmp_env, ((_tmp_s32_result==0)? MV_EC_RESOURCE_LEAK : _tmp_s32_result))
/**
 * @brief mjson内部核心实现，不要直接调用
 * 
 */
#define _mjson_build(base_anon, pout, max, out_len, ...)        \
do {                                                            \
    mv_v8ptr_t _tmp_pv8_mjson_build = NULL;                     \
    jmp_buf    _tmp_env;                                        \
    mv_s32_t   _tmp_s32_mjson_size  = max;                      \
    mv_s32_t   _tmp_s32_result      = 0;                        \
    mv_s32_t   _tmp_s32_off         = 0;                        \
    __attribute__((unused)) mv_v8_t _tmp_av8_num_str[64] = {0}; \
    _tmp_s32_result                 = setjmp(_tmp_env);         \
    if (_tmp_s32_result != 0) {                                 \
        out_len = _tmp_s32_result;                              \
        break;                                                  \
    }                                                           \
    if (pout) {                                                 \
        _tmp_pv8_mjson_build = pout;                            \
    }  else {                                                   \
        pout = _tmp_pv8_mjson_build = mvos_zalloc(max);         \
    }                                                           \
    do{base_anon(__VA_ARGS__);}while(0);                        \
    if (_tmp_s32_result < 0) {                                  \
        out_len = _tmp_s32_result;                              \
    } else {                                                    \
        out_len = _tmp_s32_off;                                 \
        if ((_tmp_s32_off > 0)                                  \
        && (_tmp_pv8_mjson_build[_tmp_s32_off-1] == ',')) {     \
            _tmp_pv8_mjson_build[_tmp_s32_off-1] = '\0';        \
            _tmp_s32_off--;                                     \
            out_len--;                                          \
        }                                                       \
    }                                                           \
} while (0);
/**
 * @brief 开始一个新的对象类型JSON构建
 * 
 * @param pout      [out] json输出缓存地址(这个参数需要是指针，不能直接用数组)
 * @param max        [in] 输出缓冲大小
 * @param out_len    [in] 实际输出json长度
 * @param ...        [in] json操作嵌套代码
 * @return 构建结果，根据out_len判断
 * - success : out_len > 0
 * -  failed : MV_EC_RESOURCE_LEAK (缓存大小不足)
 *             MV_EC_OUT_OF_RANGE  (JSON格式非法)
 * @note 当pout输入的变量指向NULL，会自动按照max申请内存，需要用户自行判断释放
 * @note 下面所有mjson的嵌套代码封装，均需要在build范围内调用，自动关联处理
 */
#define mvt_mjson_object_build(pout, max, out_len, ...)  _mjson_build(mvt_mjson_anon_obj, pout, max, out_len, __VA_ARGS__)
/**
 * @brief 开始一个新的数组类型JSON构建
 * 
 * @note 参数和用法参照"mvt_mjson_object_build"
 */
#define mvt_mjson_array_build(pout, max, out_len, ...)   _mjson_build(mvt_mjson_anon_arr, pout, max, out_len, __VA_ARGS__)
/**
 * @brief (JSON操作嵌套代码封装:)JSON当前可用缓存大小
 * 
 * @note 需要在build范围内使用，自动关联返回
 */
#define mvt_mjson_volatile_valid (_tmp_s32_mjson_size-_tmp_s32_off)
/**
 * @brief (JSON操作嵌套代码封装:)JSON当前地址获取
 * 
 * @note 需要在build范围内使用，自动关联返回
 */
#define mvt_mjson_volatile_ptr   (_tmp_pv8_mjson_build+_tmp_s32_off)
/**
 * @brief (JSON操作嵌套代码封装:)JSON存档点刷新
 * 
 * @note 需要在build范围内使用，自动关联处理
 * @note 可用于回溯
 */
/** 用户自定义存档点（入参取出当前位置） */
#define mvt_mjson_back_anchor_update(anchor) anchor = _tmp_s32_off;
/**
 * @brief (JSON操作嵌套代码封装:)JSON存档点回溯
 * 
 * @note 需要在build范围内使用，自动关联处理
 * @note 可用于在拼接了某些不需要的内容时，回溯到上一个存档点进行后续操作
 * @attention 注意！不要跨域回溯存档点（即只能跳转同一级存档点），否则json结构会出现异常
 */
#define mvt_mjson_back_anchor_jump(anchor)   _tmp_s32_off = anchor;
/**
 * @brief (JSON操作嵌套代码封装:)JSON灵活数据填充
 * 
 * @param key        [in] 灵活数据key名称（可选，不需要key时，传""即可）
 * @param f_source   [in] 灵活数据处理函数（此处定义支持变长参，固定至少两个参数，缓存buffer和buffer当前可用大小
 * @param ...        [in] 灵活数据处理函数可变定义参数
 *
 * @note 需要在build范围内使用，自动关联处理
 * @note 一般用于需要复杂操作，或者分离构建子对象内容时使用；常见比如子object
 */
#define mvt_mjson_volatile(key, bfacts, f_source, ...) \
if (key[0]) {                                                                                                               \
    _tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\"%s\":", key); \
    if (_tmp_s32_result < 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                      \
}                                                                                                                           \
bfacts;                                                                                                                     \
_tmp_s32_result = f_source;                                                                                                 \
if (_tmp_s32_result < 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                          \
__VA_ARGS__;                                                                                                                \
if (_tmp_pv8_mjson_build[_tmp_s32_off-1] != ',') {                                                                          \
    _tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), ",");            \
    if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                     \
}

/**
 * @brief (JSON操作嵌套代码封装:)JSON有名对象
 * 
 * @param key        [in] 对象key名称
 * @param ...        [in] json操作嵌套代码
 *
 * @note 需要在build范围内使用，自动关联处理
 */
#define mvt_mjson_obj(key, ...)                                                                                         \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\"%s\":{", key);\
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                              \
__VA_ARGS__;                                                                                                            \
if (_tmp_pv8_mjson_build[_tmp_s32_off-1] == ',') {_tmp_s32_off-=1;}                                                     \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "},");           \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON无名对象
 * 
 * @param ...        [in] json操作嵌套代码
 *
 * @note 需要在build范围内使用，自动关联处理
 */
#define mvt_mjson_anon_obj(...)                                                                                       \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "{");          \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                            \
__VA_ARGS__;                                                                                                          \
if (_tmp_pv8_mjson_build[_tmp_s32_off-1] == ',') {_tmp_s32_off-=1;}                                                   \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "},");         \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON数组
 * 
 * @param key        [in] 数组key名称
 * @param ...        [in] json操作嵌套代码
 *
 * @note 需要在build范围内使用，自动关联处理
 */
#define mvt_mjson_arr(key, ...)                                                                                         \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\"%s\":[", key);\
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                     \
__VA_ARGS__;                                                                                                            \
if (_tmp_pv8_mjson_build[_tmp_s32_off-1] == ',') {_tmp_s32_off-=1;}                                                     \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "],");           \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON无名数组
 * 
 * @param ...        [in] json操作嵌套代码
 *
 * @note 需要在build范围内使用，自动关联处理
 */
#define mvt_mjson_anon_arr(...)                                                                                         \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "[");            \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                     \
__VA_ARGS__;                                                                                                            \
if (_tmp_pv8_mjson_build[_tmp_s32_off-1] == ',') {_tmp_s32_off-=1;}                                                     \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "],");           \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON字符串
 * 
 * @param key        [in] 字符串key名称
 * @param str        [in] 字符串内容起始地址
 * @param ...        [in] （可选入参）字符串内容长度
 *
 * @note 需要在build范围内使用，自动关联处理
 * @note 当字符串内容长度不入参时，会自动处理为strlen进行临时的长度计算
 */
#define _mjson_str_len(str, len) ((#len[0] ? len : mvos_strlen(str)))
#define mvt_mjson_str(key, str, ...)                                                                                                   \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\"%s\":\"", key);              \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                                    \
_tmp_s32_result = mvt_string_transfer_json_content(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), (str), _mjson_str_len(str, __VA_ARGS__)); \
if (_tmp_s32_result < 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                                    \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\",");                         \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON无名字符串
 * 
 * @param str        [in] 字符串内容起始地址
 * @param ...        [in] （可选入参）字符串内容长度
 *
 * @note 需要在build范围内使用，自动关联处理
 * @note 当字符串内容长度不入参时，会自动处理为strlen进行临时的长度计算
 */
#define mvt_mjson_anon_str(str, ...)                                                                                                   \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\"");              \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                                    \
_tmp_s32_result = mvt_string_transfer_json_content(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), (str), _mjson_str_len(str, __VA_ARGS__)); \
if (_tmp_s32_result < 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;                                                                    \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\",");                         \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON整数
 * 
 * @param key        [in] 整数key名称
 * @param num        [in] 整数数值
 *
 * @note 需要在build范围内使用，自动关联处理
 * @note 所有类型数值都会归一化为s64进行处理
 */
#define mvt_mjson_num(key, num)                                                                                                                  \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\"%s\":%s,", key, mvos_integer2str_scal((num),_tmp_av8_num_str,sizeof(_tmp_av8_num_str),10,MVOS_INT2STR_STYLE_NONE,0));  \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON无名整数
 * 
 * @param num        [in] 整数数值
 *
 * @note 需要在build范围内使用，自动关联处理
 * @note 所有类型数值都会归一化为s64进行处理
 */
#define mvt_mjson_anon_num(num)                                                                                                                  \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "%s,", mvos_integer2str_scal((num),_tmp_av8_num_str,sizeof(_tmp_av8_num_str),10,MVOS_INT2STR_STYLE_NONE,0));  \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON浮点数
 * 
 * @param key        [in] 浮点数key名称
 * @param double     [in] 浮点数数值
 *
 * @note 需要在build范围内使用，自动关联处理
 * @note 所有类型数值都会归一化为f64进行处理
 */
#define mvt_mjson_double(key, double)                                                                                                            \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\"%s\":%f,", key, (mv_f64_t){(double)}); \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON布尔值
 * 
 * @param key        [in] 布尔值key名称
 * @param bool       [in] 布尔值数值
 *
 * @note 需要在build范围内使用，自动关联处理
 */
#define mvt_mjson_bool(key, bool)                                                                                                               \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "\""key"\":%s,", (bool)?"true":"false"); \
if (_tmp_s32_result <= 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;
/**
 * @brief (JSON操作嵌套代码封装:)JSON-volatile
 * 
 * @param volstr     [in] 任意内容字符串数据
 * @param num        [in] 整数数值
 *
 * @note 需要在build范围内使用，自动关联处理
 * @note 一般用于额外拼装好的arr或obj内容，直接插入到mvt_mjson_arr或mvt_mjson_obj内
 */
#define mvt_mjson_volset(volset)                                                                                                               \
_tmp_s32_result = mvos_snprintf(_tmp_pv8_mjson_build+_tmp_s32_off, (_tmp_s32_mjson_size-_tmp_s32_off), "%s", volset);                          \
if (_tmp_s32_result < 0) {_mjson_break;} _tmp_s32_off += _tmp_s32_result;

MVCXX_EXTERN_END

#endif
